﻿using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;

namespace Luka;

/// <summary>
/// 拒绝快速频繁操作
/// </summary>
[NotScanned, AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public sealed class OffsetQuickAttribute : Attribute, IAsyncActionFilter
{
    /// <summary>
    /// 内存缓存
    /// </summary>
    private static readonly MemoryCache _cache = new(new MemoryCacheOptions());

    /// <summary>
    /// 过期时间
    /// </summary>
    public int Second { get; set; } = 3;

    /// <summary>
    /// 构造函数
    /// </summary>
    public OffsetQuickAttribute()
    {
    }

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="Second">过期时间：默认3秒</param>
    public OffsetQuickAttribute(int second = 3)
    {
        Second = second;
    }

    /// <summary>
    /// 重写方法
    /// </summary>
    /// <param name="context"></param>
    /// <param name="next"></param>
    /// <returns></returns>
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        try
        {
            //自定义键名
            string key = $"{CacheConst.Cache_Throttle}{context.HttpContext.Request.Path}&{context.HttpContext.Connection.RemoteIpAddress}";
            //分布式缓存
            var distributedCache = context.HttpContext.RequestServices.GetService<IDistributedCache>();
            if (distributedCache != null)
            {
                var value = await distributedCache.GetStringAsync(key);
                if (!string.IsNullOrWhiteSpace(value))
                {
                    context.Result = context.ReturnResult("请求频繁，请稍后尝试...", true);
                }
                else
                {
                    await distributedCache.SetStringAsync(key, key, new DistributedCacheEntryOptions
                    {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(Second)
                    });
                    await next();
                }
            }
            else
            {
                if (_cache.TryGetValue(key, out _))
                {
                    context.Result = context.ReturnResult("请求频繁，请稍后尝试...", true);
                }
                else
                {
                    _cache.Set(key, key, TimeSpan.FromSeconds(Second));
                    await next();
                }
            }
            _ = Task.CompletedTask;
        }
        catch (Exception)
        {
            throw;
        }
    }
}